using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

using KLATencor.CommonApp.Infrastructure.StateMachine;

using Syncfusion.Windows.Forms.Diagram;
using Syncfusion.Windows.Forms.Diagram.Controls;

using StateMachine_Graphical_Editor.Forms;
using StateMachine_Graphical_Editor.Utils.Forms_RunTime_Managment;

//Graphical representation of a simple state:
namespace StateMachine_Graphical_Editor.Shapes
{
    /// <summary>
    /// Provides a graphical representation of a single logical state in the state machine.
    /// </summary>
    public class GState : RoundRect
    {
        #region Members

        private PaletteGroupView palette;

        /// <summary>
        /// The StatesForm consisting of this object
        /// </summary>
        private readonly StatesForm form;

        //TODO: when editing KLA State's properties feature is added - remove these
        //state descriptors
        private bool currentState = false;
        private bool isInitialState = false;
        private bool isFinalState = false;
        private string type = "Basic";
        private bool useHistory = false;
        private string abbervName;
        private string customStateFile;
        private string customStateClass;
        private string action;

        private long id = -1; 
        
        /// <summary>
        /// reference to the state from the machine which this graphical element represents
        /// </summary>
        private State logicState;
        private readonly StateMachine machine;
        private int numOfSubStates = 0;

        #region Constants:

        private const String PALETTE_NAME = "Simple State";

        #endregion

        #endregion

        #region C'tors:

        public GState(PaletteGroupView palette, State state)
            : base((RoundRect)palette.Palette.Nodes.FindNodeByName(PALETTE_NAME))
        {
            base.Name = state.Name;

            this.logicState = state;
            this.palette = palette;
            this.machine = state.StateMachine;
            initFields();
            
        }

        public GState(PaletteGroupView palette, State state, StatesForm owner)
            : this(palette, state)
        {
            this.form = owner;
        }

        public GState(RoundRect baseShape)
            : base(baseShape)
        {
            this.Labels[0].Text = this.Name;
        }

        public GState(RoundRect baseShape, StatesForm owner)
            : this(baseShape)
        {
            this.form = owner;
        }

        private void initFields()
        {
            if (null != logicState)
            {
                this.abbervName = logicState.AbbrevName;
                this.useHistory = logicState.UseHistory;
                this.id = logicState.ID;
                if (logicState.Equals(machine.InitialState))
                    this.isInitialState = true;

                //set state's lable (only one in label collection):
                this.Labels[0].Text = Name;
            }
            this.customStateClass = "";
            this.customStateFile = "";
        }

        #endregion

        #region Getters/Setters:

        public bool CurrentState
        {
            get { return this.currentState; }
            set 
            {
                System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
                this.currentState = value;

                if (currentState)
                {
                    //update appearance on the diagram form
                    this.form.CurrentGState = this;
                    this.LineStyle.LineColor = Color.Red;
                    this.FillStyle.Color = Color.Red;
                    
                    //if has substates, open the subStates form
                    if (hasSubStates())
                    {
                        SubStatesForm subStatesForm = new SubStatesForm(this.logicState, null, DisplayModes.VIEW_MODE);
                        Utils.Forms_RunTime_Managment.FormsManager.getManager().addAndShow(subStatesForm);
                    }
                    //if final and a subState, alert and close its form
                    if (isFinalState)
                    {
                        if (form is MainForm)
                            MessageBox.Show(
                                "A final state was reached.",
                                "Final State Reached",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information);
                        else //form is SubStateForm
                        {
                            DialogResult res = MessageBox.Show(
                                "A final state was reached.\nDo you want to close this display?",
                                "Final State Reached",
                                MessageBoxButtons.YesNo,
                                MessageBoxIcon.Information);
                            if (res == DialogResult.Yes)
                                form.Close();
                        }
                    }
                }
                else //not current state
                {
                    this.LineStyle.LineColor = Color.Black;
                    this.FillStyle.Color = Color.White;
                }
                System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = true;
            }  
        }

        public bool IsInitialState
        {
            get { return isInitialState; }
            set { isInitialState = value; }
        }

        public bool IsFinalState
        {
            get { return isFinalState; }
            set { isFinalState = value; }
        }

        public long ID
        {
            get { return id; }
            set { this.id = value; }
        }

        public string AbbrevName
        {
            get { return abbervName; }
            set { abbervName = value; }
        }

        public bool UseHistory
        {
            get { return useHistory; }
            set { useHistory = value; }
        }

        public string CustomStateFile
        {
            get { return customStateFile; }
            set { customStateFile = value; }
        }

        public string CustomStateClass
        {
            get { return customStateClass; }
            set { customStateClass = value; }
        }

        public string Action
        {
            get { return action; }
            set { action = value; }
        }

        public State LogicState
        {
            get { return logicState; }
            set { logicState = value; }
        }

        public StatesForm Form
        {
            get { return this.form; }
        }

        public String StateType
        {
            get { return type; }
            set { type = value; }
        }

        public String ParentName
        {
            get { return logicState != null && logicState.Parent!=null ? logicState.Parent.Name : ""; }
        }

        public State ParentState
        {
            get { return logicState != null ? logicState.Parent: null; }
        }

        public String InitialSubStateName
        {
            get { return logicState!=null ? logicState.InitialSubstateName : ""; }
        }

        #endregion

        #region OnTransitionOccured event handler:

        public void handleEventForGState(StateChangeEventArgs args)
        {
            //this check is to make sure tht only the current form's nodes response to the event:
            if (!FormsManager.getManager().isTopForm(form))
                return;

            State currentTmp = null;

            //check if the state is the source state
            if (args.OldState != null && this.Name.Equals(args.OldState.Name))
            {
                //check if this is the parent state
                if (this.Name.Equals(form.getName()))
                {
                    //if dest. state is the parent's initial - the initial will deal it:
                    if (args.NewState != null && (currentTmp = LogicState.Substates.Find(args.NewState.Name)) != null)
                        return;

                    //else - global transition occured from parent:
                    SubStatesForm newForm = new SubStatesForm(args.NewState.Parent, args.NewState, DisplayModes.VIEW_MODE);
                    FormsManager.getManager().changeForms(args.Transition, newForm);
                }
                else
                    this.CurrentState = false;
            }
            //check if the state is the destination state 
            else if (args.NewState != null && this.Name.Equals(args.NewState.Name))
            {
                this.CurrentState = true;
            }
            //check if the target state is in this state:
            else if (args.NewState != null && !this.Name.Equals(form.getName()) && (currentTmp = LogicState.Substates.Find(args.NewState.Name)) != null)
            {
                //the current state is in this state:
                SubStatesForm newForm = new SubStatesForm(currentTmp.Parent, currentTmp, DisplayModes.VIEW_MODE);
                FormsManager.getManager().addAndShow(args.Transition, newForm);
            }
            else //no relevance to the occured transition
                return;
        }

        #endregion

        #region Methods:

        /// <summary>
        /// Checks whether this state has sub states 
        /// </summary>
        /// <returns></returns>
        public bool hasSubStates()
        {
            numOfSubStates = 0; //reset this property
            if (logicState != null)
            {
                //count number of substates (if any):
                foreach (State sub in logicState.Substates)
                {
                    numOfSubStates++;
                }
            }

            return numOfSubStates > 0;
        }

        #region Copied from the example - "Expander":
        //draw a '+' if has subStates 
        protected override void Render(Graphics gfx)
        {
            base.Render(gfx);

            // draw helper plus/minus symbol
            DrawPlusMinus(gfx);
        }

        private void DrawPlusMinus(Graphics gfx)
        {
            if (hasSubStates())
            {
                int length = 10;
                SizeF szOffset = new SizeF(length, length);

                // horizontal
                PointF[] ptsHorizontal = new PointF[]
					{
						new PointF( szOffset.Width -length/2, szOffset.Height ),
						new PointF( szOffset.Width + length/2, szOffset.Height )
					};

                // vertical
                PointF[] ptsVertical = new PointF[]
					{
						new PointF( szOffset.Width, szOffset.Height-length/2 ),
						new PointF( szOffset.Width, szOffset.Height + length/2 )
					};

                using (Pen penHightlight = new Pen(Color.Gray, 1))
                using (Pen pen = new Pen(Color.Black, 2))
                {

                    gfx.DrawLine(pen, ptsVertical[0], ptsVertical[1]);
                    gfx.DrawLine(penHightlight, ptsVertical[0], ptsVertical[1]);

                    gfx.DrawLine(pen, ptsHorizontal[0], ptsHorizontal[1]);
                    gfx.DrawLine(penHightlight, ptsHorizontal[0], ptsHorizontal[1]);
                }
            }
        }
        #endregion

        #endregion
    }
}
